﻿//This C# code file was released under the Ms-PL license
//http://www.opensource.org/licenses/ms-pl.html
//This script was originally intended for use with Microsoft Dynamics AX
//and maintained and distributed as a project on CodePlex
//http://dynamicsaxbuild.codeplex.com

using System;
using System.Collections.Generic;
using System.Text;
using System.Activities;
using Microsoft.Win32;
using System.ServiceProcess;
using Microsoft.TeamFoundation.Build.Client;

namespace AXTFSBuildLibrary
{
    public enum DynamicsAXVersion
    {
        AX2009 = 50,
        AX2012 = 60
    }

    /// <summary>
    /// The ServerConfig class initializes values relating to the AOS configuration.
    /// </summary>
    [BuildActivity(HostEnvironmentOption.All)]
    public class ServerConfig : CodeActivity
    {
        /// <summary>
        /// Name of the AOS server (machine)
        /// </summary>
        [RequiredArgument]
        public InArgument<string> ServerName { get; set; }
        /// <summary>
        /// The AOS port number
        /// </summary>
        [RequiredArgument]
        public InArgument<UInt16> PortNumber { get; set; }
        /// <summary>
        /// The Dynamics AX version
        /// </summary>
        [RequiredArgument]
        public InArgument<DynamicsAXVersion> Version { get; set; }

        /// <summary>
        /// The filesystem path of the server binaries directory.
        /// </summary>
        public OutArgument<string> ServerBinPath { get; set; }
        /// <summary>
        /// The filesystem path of the server application file directory.
        /// </summary>
        public OutArgument<string> ServerApplicationPath { get; set; }
        /// <summary>
        /// The filesystem path of the server label files directory.
        /// </summary>
        public OutArgument<string> ServerLabelFilePath { get; set; }
        /// <summary>
        /// The service identifier of the AOS service (e.g. "AOS60$01")
        /// </summary>
        public OutArgument<string> ServerServiceIdentifier { get; set; }

        private const string aosRegistryPath = @"SYSTEM\CurrentControlSet\services\Dynamics Server\";

        protected override void Execute(CodeActivityContext context)
        {
            string serverName = ServerName.Get(context);
            UInt16 portNumber = PortNumber.Get(context);
            string aosRegistryPath = ServerConfig.aosRegistryPath;

            // Initialize the full registry path.
            switch (Version.Get(context))
            {
                case DynamicsAXVersion.AX2009:
                    aosRegistryPath = aosRegistryPath + "5.0";
                    break;
                case DynamicsAXVersion.AX2012:
                    aosRegistryPath = aosRegistryPath + "6.0";
                    break;
            }

            RegistryKey aosEntries;

            // The code technically supports execution from a remote machine
            // This is untested and the usefulness is questionable

            if (serverName != System.Environment.MachineName)
            {
                // Open the registry on the remote machine
                aosEntries = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, serverName);
                // Get the list of servers running on the remote machine.
                aosEntries = aosEntries.OpenSubKey(aosRegistryPath);
            }
            else
            {
                // Get the list of servers running on this machine.
                aosEntries = Registry.LocalMachine.OpenSubKey(aosRegistryPath);
            }

            // Get subkeys which contain the different AOS instances
            string[] aosRegistryEntries = aosEntries.GetSubKeyNames();

            // Try and find the windows service identifier for the AOS on the given server/portnumber
            bool foundService = false;
            foreach (string aosRegistryEntry in aosRegistryEntries)
            {
                // Open the AOS instance root key
                RegistryKey aosRootKey = Registry.LocalMachine.OpenSubKey(aosRegistryPath + @"\" + aosRegistryEntry);
                // Use the 'current' key value to find the current settings for the instance
                RegistryKey aosInstanceKey = Registry.LocalMachine.OpenSubKey(aosRegistryPath + @"\" + aosRegistryEntry + @"\" + aosRootKey.GetValue("Current"));
                // Check if this instance is tied to the port the AOS of interest is on
                if (aosInstanceKey.GetValue("Port").Equals(portNumber.ToString()))
                {
                    if (foundService)
                    {
                        // The port number matches, but we've already found another service entry running on the same port.
                        // Can't proceed because the port number was not strong enough to uniquely identify a single service.
                        throw new Exception("Multiple service instances found running on port " + portNumber);
                    }

                    foundService = true;

                    switch (Version.Get(context))
                    {
                        case DynamicsAXVersion.AX2009:
                            ServerServiceIdentifier.Set(context, "AOS50$" + aosRegistryEntry);
                            break;
                        case DynamicsAXVersion.AX2012:
                            ServerServiceIdentifier.Set(context, "AOS60$" + aosRegistryEntry);
                            break;
                    }

                    ServerBinPath.Set(context, aosInstanceKey.GetValue("bindir"));
                    ServerApplicationPath.Set(context, aosInstanceKey.GetValue("directory"));
                    ServerLabelFilePath.Set(context, aosInstanceKey.GetValue("directory") + @"\Appl\Standard");
                }
            }

            if (!foundService)
            {
                throw new Exception("Could not find configuration for server running on port " + portNumber);
            }
        }
    }
}
